此系列文章是以我的業餘專案: Kimoji 作為範例。
這款以純 Jetpack Compose 撰寫的 side project,已經在 Google Play 上架。 歡迎試玩!
立馬下載
在昨天的文章中,因為我們已經將日記清單 hoist 到 screen level,所以我們可以修改 Journal
composable function,來移除日記清單的 default parameter。接著再新增一個 lambda 函式參數 onDelete
(接收要刪除的 Diary
)。然後把 onDelete
傳遞至 Diary
。
@Composable
fun Journal(
modifier: Modifier = Modifier,
diaries: List<Diary>,
onDelete: (Diary) -> Unit
) {
LazyColumn(modifier = modifier) {
items(
items = diaries,
key = { diary -> diary.id }
) { task ->
Diary(notes = diary.notes, onDelete = { onDelete(diary) })
}
}
}
在上面的程式碼中,items
方法會收到 key
參數。根據預設,每個 item 的狀態都會與 item 在清單中的位置對應。
在 mutable list 的資料內容有變時,這樣就會發生問題,因為變更位置的 item 就等同於喪失 remember 的狀態。
因此我們可以使用每個 Diary
的 id
當做每個 item 的 key,就能輕鬆解決問題。
如果想進一步瞭解清單中的 item keys,請看官方說明文件。
接著定義一個 stateful Diary
composable:加入 onDelete
lambda 函式作為 Diary
的參數並進行呼叫。
@Composable
fun Diary(
modifier: Modifier = Modifier,
notes: String,
onDelete: () -> Unit
) {
var checkedState by rememberSaveable { mutableStateOf(false) }
Diary(
modifier = modifier,
notes = notes,
checked = checkedState,
onCheckedChange = { newValue -> checkedState = newValue },
onDelete = onDelete
)
}
現在這個功能已經完成,現在可以從日記清單中刪除項目了。
只要按下每一篇日記上的「刪除」,事件會往上傳遞到持有該狀態的日記清單,然後移除清單內的日記,並觸發 Compose recompose 畫面。
如果我們嘗試使用 rememberSaveable()
在 DiaryScreen
裡面儲存清單,就會發生 runtime exception:
cannot be saved using the current SaveableStateRegistry. The default implementation only supports types which can be stored inside the Bundle. Please consider implementing a custom Saver for this class and pass it to rememberSaveable().
這個錯誤說明我們需要提供 custom saver。但是,最好不要使用 rememberSaveable
儲存需要長時間 serialize 或 deserialize 的大量資料或複雜的資料結構。
當使用 Activity
的 onSaveInstanceState
時,也需要遵守一樣的規定,詳情請參閱儲存 UI 狀態說明文件。如果要實現這個需求,需要採用其他儲存機制。可以參閱官方說明文件,瞭解其他的保留 UI 狀態方法。
接下來幾天,我們要瞭解 ViewModel
在 state holder 方面扮演的角色。
此系列文章是以我的業餘專案:Kimoji 為範例。
Kimoji 是一款心情日記 App,讓你用可愛的 emoji 來撰寫你的心情日記。現在就來試試這款設計精美的微日記吧!
立馬下載
Reference: https://developer.android.com/codelabs/jetpack-compose-state